package org.theSeed.springShardingDataSource.config;

import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.sql.DataSource;
import lombok.Generated;
import org.apache.shardingsphere.core.yaml.swapper.MasterSlaveRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.core.yaml.swapper.ShardingRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.core.yaml.swapper.impl.ShadowRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.encrypt.yaml.swapper.EncryptRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.shardingjdbc.api.EncryptDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.api.MasterSlaveDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.api.ShadowDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.spring.boot.common.SpringBootPropertiesConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.encrypt.EncryptRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.encrypt.SpringBootEncryptRuleConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.masterslave.MasterSlaveRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.masterslave.SpringBootMasterSlaveRuleConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.shadow.ShadowRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.shadow.SpringBootShadowRuleConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.ShardingRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.SpringBootShardingRuleConfigurationProperties;
import org.apache.shardingsphere.transaction.spring.ShardingTransactionTypeScanner;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.theSeed.dataSource.pojo.constant.DataSourceNameConstant;
import org.theSeed.springDatasouceProp.config.SpringDataSourceConfig;
import org.theSeed.springDatasouceProp.contract.BaseDataSourceAddAware;
import org.theSeed.springDatasouceProp.contract.impl.BaseDataSourceAddAwareImpl;
import org.theSeed.springDatasouceProp.pojo.prop.SeedDataSourceProp;

@Configuration
@ComponentScan({"org.apache.shardingsphere.spring.boot.converter"})
@EnableConfigurationProperties({SpringBootShardingRuleConfigurationProperties.class, SpringBootMasterSlaveRuleConfigurationProperties.class, SpringBootEncryptRuleConfigurationProperties.class, SpringBootPropertiesConfigurationProperties.class, SpringBootShadowRuleConfigurationProperties.class})
@ConditionalOnProperty(
        prefix = "spring.shardingsphere",
        name = {"enabled"},
        havingValue = "true",
        matchIfMissing = true
)
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
@AutoConfigureAfter({SpringDataSourceConfig.class})
public class SeedShardingSpringBootConfiguration {
    @Generated
    public SeedShardingSpringBootConfiguration(SeedDataSourceProp seedDataSourceProp,SpringBootShardingRuleConfigurationProperties shardingRule, SpringBootMasterSlaveRuleConfigurationProperties masterSlaveRule, SpringBootEncryptRuleConfigurationProperties encryptRule, SpringBootShadowRuleConfigurationProperties shadowRule, SpringBootPropertiesConfigurationProperties props) {
        this.seedDataSourceProp = seedDataSourceProp;
        this.shardingRule = shardingRule;
        this.masterSlaveRule = masterSlaveRule;
        this.encryptRule = encryptRule;
        this.shadowRule = shadowRule;
        this.props = props;
        this.dataSourceMap.putAll(seedDataSourceProp.getDataSourceMap());
    }

    private SeedDataSourceProp seedDataSourceProp;

    private final SpringBootShardingRuleConfigurationProperties shardingRule;
    private final SpringBootMasterSlaveRuleConfigurationProperties masterSlaveRule;
    private final SpringBootEncryptRuleConfigurationProperties encryptRule;
    private final SpringBootShadowRuleConfigurationProperties shadowRule;
    private final SpringBootPropertiesConfigurationProperties props;
    private final Map<String, DataSource> dataSourceMap = new LinkedHashMap();


    @Bean
    @Conditional({ShardingRuleCondition.class})
    public BaseDataSourceAddAware shardingDataSource() throws SQLException {
        return new BaseDataSourceAddAwareImpl(seedDataSourceProp,DataSourceNameConstant.SHARDING_DATASOURCE_NAME,ShardingDataSourceFactory.createDataSource(this.dataSourceMap, (new ShardingRuleConfigurationYamlSwapper()).swap(this.shardingRule), this.props.getProps()));
    }

    @Bean
    @Conditional({MasterSlaveRuleCondition.class})
    public BaseDataSourceAddAware masterSlaveDataSource() throws SQLException {
        return new BaseDataSourceAddAwareImpl(seedDataSourceProp,DataSourceNameConstant.SHARDING_DATASOURCE_NAME,MasterSlaveDataSourceFactory.createDataSource(this.dataSourceMap, (new MasterSlaveRuleConfigurationYamlSwapper()).swap(this.masterSlaveRule), this.props.getProps()));
    }

    @Bean
    @Conditional({EncryptRuleCondition.class})
    public BaseDataSourceAddAware encryptDataSource() throws SQLException {
        return new BaseDataSourceAddAwareImpl(seedDataSourceProp,DataSourceNameConstant.SHARDING_DATASOURCE_NAME,EncryptDataSourceFactory.createDataSource((DataSource)this.dataSourceMap.values().iterator().next(), (new EncryptRuleConfigurationYamlSwapper()).swap(this.encryptRule), this.props.getProps()));
    }

    @Bean
    @Conditional({ShadowRuleCondition.class})
    public BaseDataSourceAddAware shadowDataSource() throws SQLException {
        return new BaseDataSourceAddAwareImpl(seedDataSourceProp,DataSourceNameConstant.SHARDING_DATASOURCE_NAME,ShadowDataSourceFactory.createDataSource(this.dataSourceMap, (new ShadowRuleConfigurationYamlSwapper()).swap(this.shadowRule), this.props.getProps()));
    }

    @Bean
    public ShardingTransactionTypeScanner shardingTransactionTypeScanner() {
        return new ShardingTransactionTypeScanner();
    }
}
